package com.runvp.service.biz.handler;

import com.runvp.common.enums.DeviceType;
import com.runvp.common.model.vo.BizIndexTjVO;
import com.runvp.common.util.BigDecimalUtil;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.DateUtils;
import com.runvp.service.biz.domain.BizDevice;
import com.runvp.service.biz.domain.BizIndexTj;
import com.runvp.service.biz.service.IBizIndexTjService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Component
public class TjHandler {

    @Autowired
    private IBizIndexTjService bizIndexTjService;

    /**
     * 汇总统计
     *
     * @param query
     * @return BizIndexTjVO
     */
    public BizIndexTjVO all(BizIndexTj query) {
        BizIndexTj tj = bizIndexTjService.all(query);
        BizIndexTjVO vo = new BizIndexTjVO();
        if (null == tj) {
            vo.setAmount(BigDecimal.ZERO);
            vo.setCount(0L);
            return vo;
        }
        BeanUtils.copyProperties(tj, vo);
        return vo;
    }

    /**
     * 构建统计结果
     *
     * @param bizDevices
     * @param query
     * @return list
     */
    public List<BizIndexTjVO> buildVOS(List<BizDevice> bizDevices, BizIndexTj query) {
        List<BizIndexTjVO> vos = new ArrayList<>();
        if (CollectionUtils.isEmpty(bizDevices)) {
            return vos;
        }
        BizIndexTjVO vo;
        Map<String, BizIndexTjVO> ts = buildMap(query);
        for (BizDevice device : bizDevices) {
            vo = ts.get(device.getDeviceCode());
            if (null == vo) {
                vo = new BizIndexTjVO();
                vo.setDeviceCode(device.getDeviceCode());
                vo.setAmount(BigDecimal.ZERO);
                vo.setCount(0L);
            }
            vo.setName(ToolUtils.toStr(device.getName()));
            vos.add(vo);
        }
        return vos;
    }

    private Map<String, BizIndexTjVO> buildMap(BizIndexTj query) {
        if (StringUtils.isNotBlank(query.getSt())) {
            query.setSt(query.getSt() + " 00:00:00");
        }
        if (StringUtils.isNotBlank(query.getEt())) {
            query.setEt(query.getEt() + " 23:59:59");
        }
        List<BizIndexTj> tjs = bizIndexTjService.indexTj(query);
        return toVOMap(tjs);
    }

    /**
     * 查询的对象转化成map,便于取值
     *
     * @param tjs
     * @return map
     */
    private Map<String, BizIndexTjVO> toVOMap(List<BizIndexTj> tjs) {
        Map<String, BizIndexTjVO> map = new HashMap<>();
        if (CollectionUtils.isEmpty(tjs)) {
            return map;
        }
        BizIndexTjVO vo;
        for (BizIndexTj tj : tjs) {
            vo = new BizIndexTjVO();
            BeanUtils.copyProperties(tj, vo);
            map.put(tj.getDeviceCode(), vo);
        }
        return map;
    }


    /**
     * 营收
     *
     * @param query
     * @return BizIndexTjVO
     */
    public BizIndexTjVO revenue(BizIndexTj query) {
        List<BizIndexTj> tjs = bizIndexTjService.revenue(query);
        BizIndexTjVO vo = new BizIndexTjVO();
        if (CollectionUtils.isEmpty(tjs)) {
            vo.setAmount(BigDecimal.ZERO);
            vo.setPtOrder(BigDecimal.ZERO);
            vo.setCloudOrder(BigDecimal.ZERO);
            vo.setCount(0L);
            return vo;
        }
        for (BizIndexTj tj : tjs) {
            if (DeviceType.WECHAT.getCode().equals(tj.getDeviceType())) {
                vo.setPtOrder(tj.getAmount());
            }
            if (DeviceType.BIG_SCREEN.getCode().equals(tj.getDeviceType())) {
                vo.setCloudOrder(tj.getAmount());
            }
        }
        vo.setAmount(BigDecimalUtil.add(vo.getCloudOrder(), vo.getPtOrder()));
        vo.setAmountMax(buildMax(vo.getAmount()));
        vo.setPtOrderMax(buildMax(vo.getPtOrder()));
        vo.setCloudOrderMax(buildMax(vo.getCloudOrder()));
        return vo;
    }

    /**
     * 汇总统计
     *
     * @param query
     * @return BizIndexTjVO
     */
    public Map<String, Object> trend(BizIndexTj query) {
        List<BizIndexTj> tjs = bizIndexTjService.trend(query);
        Map<String, Object> tjMap = tjToMap(tjs);
        //获取过去近12个月的月份
        List<String> months = DateUtils.getMonths(-12);
        Map<String, Object> map = new LinkedHashMap<>();
        //普通订单
        List<Object> ptOrder = new LinkedList<>();
        //云卡订单
        List<Object> cloudOrder = new LinkedList<>();
        for (String month : months) {
            ptOrder.add(ToolUtils.toBigDecimal(tjMap.get(DeviceType.WECHAT.getCode() + "_" + month)));
            cloudOrder.add(ToolUtils.toBigDecimal(tjMap.get(DeviceType.BIG_SCREEN.getCode() + "_" + month)));
        }
        map.put("months", months);
        map.put("ptOrder", ptOrder);
        map.put("cloudOrder", cloudOrder);
        return map;
    }

    /**
     * 近几日订单走势
     *
     * @param query
     * @return BizIndexTjVO
     */
    public Map<String, Object> nearDays(BizIndexTj query) {
        //获取近几日日期
        List<String> days = DateUtils.getDays(-query.getDays(), "yyyy-MM-dd");
        //2种类型订单，所有乘以2
        query.setDays(query.getDays() * 2);
        List<BizIndexTj> tjs = bizIndexTjService.nearDays(query);
        Map<String, Object> tjMap = tjToMap(tjs);
        Map<String, Object> map = new LinkedHashMap<>();
        //普通订单
        List<Object> ptOrder = new LinkedList<>();
        //云卡订单
        List<Object> cloudOrder = new LinkedList<>();
        for (String day : days) {
            ptOrder.add(ToolUtils.toBigDecimal(tjMap.get(DeviceType.WECHAT.getCode() + "_" + day)));
            cloudOrder.add(ToolUtils.toBigDecimal(tjMap.get(DeviceType.BIG_SCREEN.getCode() + "_" + day)));
        }
        map.put("days", days);
        map.put("ptOrder", ptOrder);
        map.put("cloudOrder", cloudOrder);
        return map;
    }

    /**
     * 今日新增用户数
     *
     * @return map
     */
    public Map<String, Object> nowdayNewAddUser() {
        List<BizIndexTj> tjs = bizIndexTjService.nowdayNewAddUser(DateUtils.getDays(-1).get(0));
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("cloudCard", 0);
        map.put("customer", 0);
        if (CollectionUtils.isEmpty(tjs)) {
            return map;
        }
        for (BizIndexTj tj : tjs) {
            map.put(tj.getType(), tj.getCount());
        }
        return map;
    }

    /**
     * 近几日订单走势
     *
     * @param query
     * @return BizIndexTjVO
     */
    public Map<String, Object> near2Days(BizIndexTj query) {
        //获取近几日日期
        List<String> days = DateUtils.getDays(-query.getDays(), "yyyy-MM-dd");
        //2种类型订单，所有乘以2
        query.setDays(query.getDays() * 2);
        List<BizIndexTj> tjs = bizIndexTjService.nearDays(query);
        Map<String, Object> tjMap = tjToMap(tjs);
        Map<String, Object> map = new LinkedHashMap<>();
        Map<String, Object> cmap;
        for (String day : days) {
            cmap = new LinkedHashMap<>();
            cmap.put("amount", sumAmount(tjMap, day));
            cmap.put("count", sumCount(tjMap, day + "_count"));
            map.put(getDayKey(day), cmap);
        }
        return map;
    }

    /**
     * 今日设备在线情况
     *
     * @param bizIndexTj
     * @return list
     */
    public Map<String, Object> nowdayDeviceOnLine(BizIndexTj bizIndexTj) {
        bizIndexTj.setDay(DateUtils.getDays(-1).get(0));
        List<BizIndexTj> tjs = bizIndexTjService.nowdayDeviceOnLine(bizIndexTj);
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("on_line", 0);
        map.put("off_line", 0);
        if (CollectionUtils.isEmpty(tjs)) {
            return map;
        }
        for (BizIndexTj tj : tjs) {
            map.put(tj.getType(), tj.getCount());
        }
        return map;
    }

    /**
     * 总金额计算
     *
     * @param tjMap
     * @param day
     * @return BigDecimal
     */
    private BigDecimal sumAmount(Map<String, Object> tjMap, String day) {
        BigDecimal ordinary = ToolUtils.toBigDecimal(tjMap.get(DeviceType.WECHAT.getCode() + "_" + day));
        BigDecimal cloudCard = ToolUtils.toBigDecimal(tjMap.get(DeviceType.BIG_SCREEN.getCode() + "_" + day));
        return BigDecimalUtil.add(ordinary, cloudCard);
    }

    /**
     * 总数量计算
     *
     * @param tjMap
     * @param day
     * @return long
     */
    private long sumCount(Map<String, Object> tjMap, String day) {
        long ordinary = ToolUtils.objTOLong(tjMap.get(DeviceType.WECHAT.getCode() + "_" + day));
        long cloudCard = ToolUtils.objTOLong(tjMap.get(DeviceType.BIG_SCREEN.getCode() + "_" + day));
        return ordinary + cloudCard;
    }

    /**
     * 获取是今日还是昨日
     *
     * @param day
     * @return str
     */
    private String getDayKey(String day) {
        if (day.equals(DateUtils.getDays(-1, "MM-dd").get(0))) {
            return "nowday";
        }
        if (day.equals(DateUtils.getDays(-2, "MM-dd").get(0))) {
            return "yesterday";
        }
        return day;
    }

    /**
     * 统计转 map
     *
     * @param tjs
     * @return map
     */
    private Map<String, Object> tjToMap(List<BizIndexTj> tjs) {
        Map<String, Object> map = new LinkedHashMap<>();
        if (CollectionUtils.isEmpty(tjs)) {
            return map;
        }
        for (BizIndexTj tj : tjs) {
            map.put(tj.getDeviceType(), tj.getAmount());
            map.put(tj.getDeviceType() + "_count", tj.getCount());
        }
        return map;
    }

    /**
     * 计算最大值
     *
     * @param amount
     * @return BigDecimal
     */
    private long buildMax(BigDecimal amount) {
        amount = ToolUtils.toBigDecimal(amount);
        long baseBs = 1000;
        long bs = amount.longValue() / baseBs;
        if (bs >= 1) {
            return bs * 1000 + baseBs;
        }
        return baseBs;
    }

}
